//
//  AjaxTransfer.swift
//  AjaxRequestResponse
//
//  Created by Bob.Su on 16/2/22.
//  Copyright © 2016年 infitecs. All rights reserved.
//

import Alamofire
import ObjectMapper

typealias AjaxMethod = Alamofire.Method

class AjaxRequest <ReturnDataType: Mappable> {
    var method : Alamofire.Method
    var url : String
    var parameters : [String : AnyObject]?
    var setDataMethod: ((response: AjaxResponse<ReturnDataType>) -> Void)
    
    #if DEBUG
    var isPrintJSON : Bool
    #endif
    
    init(method: Alamofire.Method,
        url: String,
        parameters: [String : AnyObject]? = nil,
        setDataMethod: ((response: AjaxResponse<ReturnDataType>) -> Void),
        isPrintJSON: Bool = false) {
            
            self.method = method
            self.url = url
            self.parameters = parameters
            self.setDataMethod = setDataMethod
            #if DEBUG
                self.isPrintJSON = isPrintJSON
            #endif
    }
    
    func request() {
        Alamofire.request(method, url, parameters: parameters)
            .responseJSON(completionHandler: completeMethod)
    }
    
    func completeMethod (response: Response<AnyObject, NSError>) -> Void {
        let ajaxResponse : AjaxResponse = AjaxResponse<ReturnDataType>(relativeRequest: self)
        if let json = response.result.value {
            #if DEBUG
                ObjectAnalyzer<AjaxResponse<ReturnDataType>>(description: "AjaxResponse").analyze(json, toObject: ajaxResponse)
                if isPrintJSON {
                    ajaxResponse.printJSON()
                }
            #else
                ObjectAnalyzer<AjaxResponse<ReturnDataType>>().analyze(json, toObject: ajaxResponse)
            #endif
        } else {
            ajaxResponse.fail = true
            #if DEBUG
                printError(url, parameters: parameters)
            #endif
        }
        setDataMethod(response: ajaxResponse)
    }
}

#if DEBUG
extension AjaxRequest {
    func printError (url: String, parameters: [String : AnyObject]?) {
        print("")
        print("请求错误")
        print("Url: \(url)")
        print("Parameters")
        if let parameters = parameters{
            for parameter in parameters {
                print("    \(parameter)")
            }
        } else {
            print("    NoParameter")
        }
    }
}
#endif

class AjaxResponse <ReturnDataType:Mappable> : Mappable {
    
    // start - 定义请求结果对象中的成员
    var error : Bool?
    var ok : Bool?
    var warning : Bool?
    
    var returnState : String?
    var returnMsg : String?
    // end
    
    // 返回此AjaxResponse对象的AjaxRequest请求对象。与AjaxRequest的request方法相关，请慎重修改。
    var relativeRequest : AjaxRequest<ReturnDataType>!
    
    // 通过修改returnDataKey的值来变更结果集成员的名称。
    var returnDataKey : String = "returnData"
    
    // returnData和returnDataJSON是必要成员，与AjaxRequest的构造方法相关，请慎重修改。
    var returnData : ReturnDataType?
    var returnDataJSON : [String : AnyObject]?
    
    // fail 表示请求失败，可能是未连接网络，服务器维护，请求超时等网络问题。与AjaxRequest中的completeMethod方法相关，请慎重修改。
    var fail : Bool?
    
    init(relativeRequest: AjaxRequest<ReturnDataType>) {
        self.relativeRequest = relativeRequest
    }
    
    required init?(_ map: Map) {
    }
    
    func mapping(map: Map) {
        // start - 根据请求结果成员，注入数据
        error       <- (map["error"], oBool2JInt())
        ok          <- (map["ok"], oBool2JInt())
        warning     <- (map["warning"], oBool2JInt())
        
        returnState <- map["returnState"]
        returnMsg   <- map["returnMsg"]
        // end
        
        // 根据 returnDataKey 将请求结果中的数据集去除。根据请求的要求，用不同的方式处理数据集。不建议修改
        #if DEBUG
            if relativeRequest.isPrintJSON {
                returnDataJSON  <- map[returnDataKey]
                return
            }
        #endif
        returnData  <- map[returnDataKey]
    }
}

// AjaxResponse 格式化输出 - 与所有的 AjaxResponse 输出相关。请慎重修改。
#if DEBUG
extension AjaxResponse {
    func printStatus () {
        let status = printAttribute("Error", error)
            + printAttribute("OK", ok)
            + printAttribute("Warning", warning)
            + printAttribute("ReturnState", returnState)
            + printAttribute("ReturnMsg", returnMsg)
        print(status)
    }
    
    func printJSON () {
        if relativeRequest.isPrintJSON {
            if let returnDataJSON = returnDataJSON {
                printAttribute("ReturnData", returnDataJSON)
            } else {
                print("No ReturnData")
                return
            }
        } else {
            print("未存储JSON数据，如果要打印JSON，请设置AjaxRequest的isPrintJSON = true")
            print("注意：请使用DEBUG条件变异")
            print("#if DEBUG")
            print("#AjaxRequest#.isPrintJSON = true")
            print("#endif")
        }
    }
    
    private func printAttribute(attributeName: String, _ attribute: AnyObject?) -> String {
        if let attributeNotNil = attribute {
            return "\(attributeName): \(attributeNotNil)\n"
        } else {
            return "\(attributeName): nil"
        }
    }
}
#endif
